/** 参数处理器类型 */
type Toptions_handlers<T extends object> = Partial<{ [key in TstringKey<T>]: { [key: string]: (value: any, t: Ttypeof, td: Etypedetail) => any } }>;
/** 参数键 与 类型 映射 */
type Toption_key_to_types_mapping<T extends object> = Map<TstringKey<T>, Array<keyof T>>;
/** 重载配置 映射 */
type Toverloading_mapping<T extends object> = Array<Array<{ key: TstringKey<T>, types: Array<string> }>>;

/** 重载构造方法类 */
abstract class Coverloading<T extends object> {

    /**
     * 创建类实例的参数
     * @description 在类基类的构造方法中进行初始化
     */
    public options: T;
    /**
     * 创建类实例的参数（重载类中处理后的参数）（仅用于测试）
     * @description 在类基类的构造方法中进行初始化
     */
    // 只在测试环境中生效
    // @ts-ignore Property 'options_after_handle' has no initializer and is not definitely assigned in the constructor.ts(2564)
    private options_after_handle: T;

    /** 类通用缓存信息 */
    private static cache: Map<string, { fn: Tfunction<any>, removeKeys: Array<string> }> = new Map();
    // ====================================================== 初始化参数 ====================================================== //
    /**
     * 默认参数
     * @param <T> 子类补充参数类型
     * @description 最基础的参数，在无参数时能够保证类正常运行，也用于其它情况作为默认参数合并。
     * @returns 默认参数
     */
    protected abstract options_default(): T;

    /**
     * 参数处理器
     * @param <T> 子类补充参数类型
     * @description 指定键指定类型的处理器返回的结果期望使用默认值时，返回 DEFAULT。
     * @returns 参数处理器
     */
    protected abstract options_handlers(): Toptions_handlers<T>;

    /**
     * 函数重载配置
     * @param <T> 子类补充参数类型
     * @param mapping 参数键 映射 类型数组
     * @description 有多少个重载方法，就需要有多少个映射关系。
     * @returns 映射关系
     */
    protected abstract overloading_mapping(mapping: Toption_key_to_types_mapping<T>): Toverloading_mapping<T>;

    /**
     * 保留 DEFAULT 值 的键
     * @param <T> 子类补充参数类型
     * @returns 键 数组
     */
    protected saveDEFAULTKeys(): Array<keyof T> { return []; }

    /**
     * 参数校验器
     * @description 只做业务逻辑校验，类型校验应在handler中进行。
     * @param options 已经归一化的参数
     */
    protected abstract options_checker(options: T): void;

    // 辅助方法
    private static _options_handler_key_<T extends object>(options_handlers: Toptions_handlers<T>, key: TstringKey<T>, t: Ttypeof) {
        if (options_handlers) {// 有处理器定义对象
            const key_handlers = options_handlers[key];
            if (key_handlers) {// 有指定键的处理器
                let key_handler = key_handlers[t];
                if (key_handler) {// 有指定类型的处理器
                    return key_handler;
                }
                // 没有指定类型的处理器，则尝试模糊匹配。
                key_handler = key_handlers[U.F.argType.any];
                if (key_handler) {
                    return key_handler;
                }
            }
        }
        // 没有找到处理
        return null;
    }

    /**
     * 构造方法
     * @param args 创建实例的参数
     * @description 创建实例时，支持多元化的参数调用，本基类只做统一行为的模板实现，需要子类进行一些特殊处理实现。
     * 
     * @description 没有传入参数                       使用默认值
     * 
     * @description 传入一个参数    DEFAULT            使用默认值
     * @description 传入一个参数    {}                 使用默认值
     * @description 传入一个参数    obj                使用参数处理器结果值覆盖默认值
     *
     * @description 传入一个参数    others             使用指定键的参数处理器覆盖默认值
     * @description 传入一个参数    others[undefined]  使用 [undefined] 作为值。它并不等同于没有传入参数。参数支持任意类型，[undefined]也作为值的形式存在，如何处理该值由子类处理器实现。
     * @description 传入一个参数    others[null]       使用 [null] 作为值。参数支持任意类型，[null]也作为值的形式存在，如何处理该值由子类处理器实现。
     * 
     * @description 传入多个参数                       子类实现的重载处理器进行处理
     * 
     * @description 没有指定键的参数处理器 或 处理器结果为DEFAULT，则使用默认值。
     */
    protected constructor(...args: Array<any>) {
        let cache = Coverloading.cache.get(this.constructor.name);// 取缓存信息
        if (!cache) {// 重载方法，只执行一次，进行缓存。
            const options_default = this.options_default();// 取默认参数
            // 删除默认值属性
            for (const key in options_default) {
                const value = options_default[key];
                if (value === DEFAULT) {
                    delete options_default[key];
                }
            }

            const options_handlers: any = this.options_handlers();// 取参数实现处理器实现

            // 将处理器配置转换成类型映射
            const key_to_types_mapping = new Map();
            for (const key in options_handlers) {
                const key_handlers = options_handlers[key];
                if (key_handlers) {// 有指定键的处理器
                    key_to_types_mapping.set(key, Object.keys(key_handlers));
                }
            }

            const impls: Array<Toverloading_impl> = [];

            // 无参处理实现
            // 单参 DEFAULT 处理实现
            // 任意参数 处理实现
            // 在最前，当有自定义实现时，会被覆盖掉。
            impls.push({
                types: [U.F.argType.rest],
                fn: () => {
                    return U.clone(options_default);// 返回默认参数副本
                }
            });

            // 为每一个配置创建一个重载函数实现
            this.overloading_mapping(key_to_types_mapping).forEach((mappings) => {
                const keys: Array<string> = [];
                const types: Array<Array<string>> = [];
                for (let i = 0; i < mappings.length; i++) {
                    const mapping = mappings[i];
                    keys.push(mapping.key);
                    types.push(mapping.types);
                }
                impls.push({
                    types: types,
                    fn: (...values: Array<any>) => {
                        const options: any = {};
                        for (let i = 0; i < keys.length; i++) {
                            const value = values[i];
                            if (value === DEFAULT) { continue; }
                            options[keys[i]] = value;
                        }
                        return cache!.fn(options);// 调用全参实现
                    }
                });
            });

            // 全参处理实现
            // 在最后，覆盖掉错误的实现。
            impls.push({
                types: [Etype.obj],
                fn: (options: any) => {
                    if (options === DEFAULT) { return U.clone(options_default); }
                    if (U.is(Etypedetail.obj_empty, options, true)) { return U.clone(options_default); }

                    options = U.merge(options_default, options);// 先合并默认参数

                    // 遍历每一个参数，调用子类实现。
                    for (const key in options) {
                        const value = options[key];
                        if (value === DEFAULT) {// 设置值指定使用 DEFAULT 则 取默认值中的值
                            const defaultValue = (options_default as any)[key];
                            if (typeof defaultValue === 'undefined') { continue; }// 默认值中没有定义的保留
                            if (defaultValue === DEFAULT) { continue; }// 默认值中定义的是 DEFAULT，保持不变。
                            options[key] = defaultValue;// 其它值则设置成默认值中的值
                            continue;
                        }

                        const t = U.typeof(value, true);
                        const handler = Coverloading._options_handler_key_(options_handlers, key, t.type);// 取对应参数处理器
                        if (handler) {// 有对应参数处理器
                            // 使用参数处理器取结果
                            const rValue = handler(value, t.type, t.detail);
                            if (rValue === DEFAULT) {// 处理器结果使用默认值 则 取默认值中的值
                                const defaultValue = (options_default as any)[key];
                                if (typeof defaultValue === 'undefined') { delete options[key]; continue; }// 默认值中没有定义的删除
                                if (defaultValue === DEFAULT) { continue; }// 默认值中定义的是 DEFAULT，保持不变。
                                options[key] = defaultValue;// 其它值则设置成默认值中的值
                                continue;
                            }
                            if (rValue === value) { continue; }// 与原值相同则跳过
                            // 替换值
                            // 处理器返回的值就应该是需要设置的值，即使是undefined、null，都应由处理器决定 => 直接赋值
                            options[key] = rValue;
                        } else {// 没有对应参数处理器
                            if (options_handlers.hasOwnProperty(key)) {// 有参数定义，则设置为默认值。
                                options[key] = DEFAULT;
                            } else {// 没有参数定义，则保留该参数。
                            }
                        }
                    }
                    return options;// 返回处理后的参数
                }
            });

            const saveDEFAULTKeys = this.saveDEFAULTKeys();

            // 创建重载函数
            cache = {
                fn: U.F.overloading(this.constructor.name, ...impls),
                removeKeys: Object.keys(options_handlers).filter(item => saveDEFAULTKeys.indexOf(item as keyof T) < 0),
            };

            Coverloading.cache.set(this.constructor.name, cache);// 缓存信息
        }

        // ==================================== 参数初始化 ==================================== //
        const options: T = cache.fn(...args);// 通过重载实现构建参数

        if (true === (globalThis as any)['isTest']) {// 测试环境下，增加备份参数，方便调试。
            this.options_after_handle = U.clone(options);
        }

        // 清除默认值
        const removeKeys = cache.removeKeys;
        for (const key in options) {
            const value = options[key];
            if (value === DEFAULT) {
                if (removeKeys.indexOf(key) >= 0) {// 有参数定义，则清除该参数。
                    delete options[key];
                } else {// 没有参数定义，则保留该参数。
                }
            }
        }

        this.options_checker(options);// 校验参数

        this.options = Object.freeze(options);// 绑定参数
    }

}
